package cz.muni.fi.pa165.musiclibrary.musiclibraryweb.components;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.event.Broadcast;
import org.apache.wicket.extensions.yui.calendar.DatePicker;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.RequiredTextField;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.form.upload.FileUpload;
import org.apache.wicket.markup.html.form.upload.FileUploadField;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.StringResourceModel;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.apache.wicket.validation.IValidatable;
import org.apache.wicket.validation.IValidator;
import org.apache.wicket.validation.ValidationError;
import org.joda.time.LocalDate;
import org.slf4j.LoggerFactory;

import cz.muni.fi.pa165.musiclibrary.api.service.IAlbumService;
import cz.muni.fi.pa165.musiclibrary.api.service.auth.IUser;
import cz.muni.fi.pa165.musiclibrary.api.service.dto.IAlbumDTO;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.LocalDateConverter;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.MusicLibrarySession;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.components.image.ImageResource;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.utils.DTOFactory;

/**
 * Panel that contains form for adding or editing an album.
 * After successful operation an event with payload {@link FormSubmittedEvent}
 * is sent.
 * 
 * @author Maros Kucbel
 * @date 2012-11-25T23:37:23+0100
 */
public final class AlbumFormPanel extends Panel {

    private IAlbumDTO album;
    @SpringBean
    private IAlbumService albumService;
    
    private List<FileUpload> fileUploads;
    
    public AlbumFormPanel(String id) {
        this(id, DTOFactory.create(IAlbumDTO.class));
    }
    
    public AlbumFormPanel(String id, IAlbumDTO artist) {
        super(id);
        this.album = artist;
    }

    @Override
    protected void onInitialize() {
        super.onInitialize();
        this.initComponents();
    }
    
    private void initComponents() {
        final FeedbackPanel feedbackPanel = new FeedbackPanel("feedbackPanel");
        feedbackPanel.setOutputMarkupId(true);
        this.add(feedbackPanel);
        Form<IAlbumDTO> form = new Form<IAlbumDTO>(ComponentIDs.FORM, Model.of(this.album)) {

            @Override
            protected void onSubmit() {
                IAlbumDTO album = this.getModelObject();
                AjaxRequestTarget target = RequestCycle.get().find(AjaxRequestTarget.class);
                if (AlbumFormPanel.this.fileUploads != null) {
                    FileUpload image = AlbumFormPanel.this.fileUploads.get(0);
                    if (image != null) {
                        String contentType = image.getContentType();
                        if (!"image/jpeg".equals(contentType)) {
                            this.error(new StringResourceModel("image.extension.jpeg", this, null).getObject());
                            target.add(feedbackPanel);
                            return;
                        }
                        byte[] buffer = new byte[1024];
                        ByteArrayOutputStream out = new ByteArrayOutputStream();
                        int length;
                        try {
                            InputStream in = image.getInputStream();
                            while ((length = in.read(buffer)) > 0) {
                                out.write(buffer, 0, length);
                            }
                            in.close();
                            out.close();
                            album.setAlbumArt(out.toByteArray());
                        } catch (IOException ex) {
                            this.error(new StringResourceModel("database.error", this, null).getObject());
                            target.add(feedbackPanel);
                            return;
                        }
                    }
                }
                try {
                    IUser user = MusicLibrarySession.get().getUser();
                    String userName = user != null ? user.getUserName() : null;
                    if (album.getIdAlbum() != null) {
                        AlbumFormPanel.this.albumService.update(album, userName);
                    } else {
                        AlbumFormPanel.this.albumService.create(album, userName);
                    }
                    this.send(this.getPage(), Broadcast.BREADTH, new FormSubmittedEvent(target));
                } catch (Exception ex) {
                    // show error
                    LoggerFactory.getLogger(AlbumFormPanel.class).error("ERROR", ex);
                    this.error(new StringResourceModel("database.error", this, null).getObject());
                    target.add(feedbackPanel);
                }
            }
            
        };
        RequiredTextField<String> titleField = new RequiredTextField<String>(ComponentIDs.TITLE, new PropertyModel<String>(form.getModelObject(), "title"));
        titleField.setOutputMarkupId(true);
        form.add(titleField);
        final TextField<LocalDate> releaseDateField = new TextField<LocalDate>(ComponentIDs.RELEASE_DATE, new PropertyModel<LocalDate>(form.getModelObject(), "releaseDate"));
        releaseDateField.add(new IValidator<LocalDate>() {
            @Override
            public void validate(IValidatable<LocalDate> validatable) {
                if (validatable.getValue() == null && StringUtils.isNotBlank(releaseDateField.getRawInput())) {
                    validatable.error(new ValidationError("Invalid date format."));
                }
            }
        });
        DatePicker datePicker = new DatePicker() {

            @Override
            protected String getDatePattern() {
                return LocalDateConverter.getDatePattern(this.getLocale());
            }
            
            @Override
            protected boolean alignWithIcon() {
                return false;
            }

            @Override
            protected boolean enableMonthYearSelection() {
                return true;
            }
            
        };
        datePicker.setShowOnFieldClick(true);
        datePicker.setAutoHide(true);
        releaseDateField.add(datePicker);
        releaseDateField.setOutputMarkupId(true);
        form.add(releaseDateField);
        
        ImageResource imageResource = new ImageResource(this.album.getAlbumArt(), "jpg");
        Image image = new Image(ComponentIDs.IMAGE, imageResource);
        image.setVisible(this.album.getAlbumArt() != null);
        form.add(image);
        
        IModel<List<FileUpload>> imageFieldModel = new PropertyModel<List<FileUpload>>(this, "fileUploads");
        FileUploadField imageInputField = new FileUploadField(ComponentIDs.IMAGE_INPUT, imageFieldModel);
        form.add(imageInputField);
        
        form.add(new AjaxSubmitLinkWithErrorClass(ComponentIDs.SUBMIT_BUTTON, form) {

            @Override
            protected void onError(AjaxRequestTarget target, Form<?> form) {
                target.add(feedbackPanel);
                super.onError(target, form);
            }
        });
        this.add(form);
    }
    
    private static final class ComponentIDs {
        private static final String FORM = "form";
        private static final String TITLE = "title";
        private static final String RELEASE_DATE = "releaseDate";
        private static final String IMAGE = "image";
        private static final String IMAGE_INPUT = "imageInput";
        private static final String SUBMIT_BUTTON = "submit";
    }
}